﻿using System;
using System.Collections.Generic;
using System.Text;
using Commerce.Common;
using System.Xml;
using System.Xml.XPath;
using System.Text.RegularExpressions;
using SubSonic;
using System.Web;
using System.Web.Security;


namespace CommerceForUmbraco.xsltExtensions
{
    public class CommerceForUmbracoExtension
    {

        public static XPathNodeIterator MemberGroups(string memberId)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                XmlElement root = (XmlElement)doc.AppendChild(doc.CreateElement("MemberGroups"));

                if (HttpContext.Current.User.Identity.IsAuthenticated)
                {
                    string[] roles = Roles.GetRolesForUser(HttpContext.Current.User.Identity.Name);

                    for (int i = 0; i < roles.Length; i++)
                    {
                        XmlElement elem = doc.CreateElement("Group");
                        XmlAttribute GroupName = doc.CreateAttribute("groupname", "");
                        GroupName.Value = roles[i];
                        elem.Attributes.Append(GroupName);

                        root.AppendChild(elem);
                    }

                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        public static XPathNodeIterator ProductDetail(string productID)
        {
            string productName = Commerce.Common.Utility.UnwindRewriteParam(productID);

            try
            {

                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement root = (XmlElement)doc.AppendChild(doc.CreateElement("Product"));

                int prodID;
                if (!int.TryParse(productID, out prodID))
                {
                    prodID = 0;
                }

                //Pull product from Subsonic object.
                Product thisProduct = null;
                //Product thisProduct = GetProduct(productID);

                foreach (Product product in new ProductCollection().Load())
                {
                    if ( product.ProductID == prodID || product.UrlFriendly.ToLower().Equals(productID.ToLower()) ) //|| product.ProductName.ToLower().Equals(productName.ToLower()))
                    {
                        thisProduct = product;

                        break;
                    }
                }

                if (thisProduct != null)
                {
                    foreach (TableSchema.TableColumnSetting col in thisProduct.GetColumnSettings())
                    {
                        string colValue = string.Empty;
                        string colName = thisProduct.GetSchema().GetColumn(col.ColumnName).PropertyName;

                        if (col.CurrentValue != null)
                            colValue = col.CurrentValue.ToString();


                        XmlAttribute ItemName = doc.CreateAttribute(colName, "");
                        ItemName.Value = colValue;
                        root.Attributes.Append(ItemName);
                    }


                    XmlElement CategoryList = (XmlElement)root.AppendChild(doc.CreateElement("CategoryList"));


                    foreach (Category category in thisProduct.GetCategoryCollection())
                    {

                        XmlElement elem = doc.CreateElement("Category");
                        XmlAttribute CategoryName = doc.CreateAttribute("CategoryName", "");
                        CategoryName.Value = category.CategoryName;
                        elem.Attributes.Append(CategoryName);

                        XmlAttribute CategoryID = doc.CreateAttribute("CategoryID", "");
                        CategoryID.Value = Convert.ToString(category.CategoryID);
                        elem.Attributes.Append(CategoryID);

                        XmlAttribute ParentID = doc.CreateAttribute("ParentID", "");
                        ParentID.Value = Convert.ToString(category.ParentID);
                        elem.Attributes.Append(ParentID);

                        XmlAttribute CategoryGUID = doc.CreateAttribute("CategoryGUID", "");
                        CategoryGUID.Value = Convert.ToString(category.CategoryGUID);
                        elem.Attributes.Append(CategoryGUID);

                        XmlAttribute UrlLocation = doc.CreateAttribute("UrlLocation", "");
                        if (ParentID.Value == "0")
                        {
                            UrlLocation.Value = Commerce.Common.Utility.GetRewriterUrl("category", category.UrlFriendly, "");
                        }
                        else
                        {
                            UrlLocation.Value = Commerce.Common.Utility.GetSubcategoryRewriterUrl("sub", category.UrlFriendly, "a", "");
                        }
                        elem.Attributes.Append(UrlLocation);

                        CategoryList.AppendChild(elem);
                    }

                }

                return doc.CreateNavigator().Select("/*");

            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// For retrieving the products in a category.
        /// </summary>
        /// <param name="categoryID"></param>
        /// <returns>XPathNodeIterator</returns>
        public static XPathNodeIterator CategoryProducts(string categoryID)
        {
            try
            {
                string categoryName = Commerce.Common.Utility.UnwindRewriteParam(categoryID);

                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement ProductList = (XmlElement)doc.AppendChild(doc.CreateElement("ProductList"));

                int catID;
                if (!int.TryParse(categoryID, out catID))
                {
                    catID = 0;
                }

                Category currentCategory = null;

                foreach (Category category in new CategoryCollection().Load())
                {
                    if (category.CategoryID == catID || category.UrlFriendly.ToLower().Equals(categoryID.ToLower())) //|| category.CategoryName.ToLower().Equals(categoryName.ToLower()))
                    {
                        currentCategory = category;

                        break;
                    }
                }


                foreach (Product prod in currentCategory.GetProductCollection())
                {
                    XmlElement elem = doc.CreateElement("Product");

                    foreach (TableSchema.TableColumnSetting col in prod.GetColumnSettings())
                    {
                        string colValue = string.Empty;
                        string colName = prod.GetSchema().GetColumn(col.ColumnName).PropertyName;

                        if (col.CurrentValue != null)
                            colValue = col.CurrentValue.ToString();


                        XmlAttribute ItemName = doc.CreateAttribute(colName, "");
                        ItemName.Value = colValue;
                        elem.Attributes.Append(ItemName);
                    }

                    ProductList.AppendChild(elem);
                }


                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }


        public static XPathNodeIterator CategoryList()
        {

            try
            {

            //Create XML object
            XmlDocument doc = new XmlDocument();

            XmlElement CategoryList = (XmlElement)doc.AppendChild(doc.CreateElement("CategoryList"));


            foreach (Category category in  new CategoryCollection().Load())
            {

                XmlElement elem = doc.CreateElement("Category");
                XmlAttribute CategoryName = doc.CreateAttribute("CategoryName", "");
                CategoryName.Value = category.CategoryName;
                elem.Attributes.Append(CategoryName);

                XmlAttribute CategoryID = doc.CreateAttribute("CategoryID", "");
                CategoryID.Value = Convert.ToString(category.CategoryID);
                elem.Attributes.Append(CategoryID);

                XmlAttribute ParentID = doc.CreateAttribute("ParentID", "");
                ParentID.Value = Convert.ToString(category.ParentID);
                elem.Attributes.Append(ParentID);

                XmlAttribute CategoryGUID = doc.CreateAttribute("CategoryGUID", "");
                CategoryGUID.Value = Convert.ToString(category.CategoryGUID);
                elem.Attributes.Append(CategoryGUID);

                XmlAttribute CategoryUrlFriendly = doc.CreateAttribute("CategoryUrlFriendly", "");
                CategoryUrlFriendly.Value = category.UrlFriendly;
                elem.Attributes.Append(CategoryUrlFriendly);

                XmlAttribute listOrder = doc.CreateAttribute("ListOrder", "");
                listOrder.Value = Convert.ToString(category.ListOrder);
                elem.Attributes.Append(listOrder);

                XmlAttribute UrlLocation = doc.CreateAttribute("UrlLocation", "");
                if (ParentID.Value == "0")
                {
                    UrlLocation.Value = Commerce.Common.Utility.GetRewriterUrl("category", category.UrlFriendly, "");
                }
                else
                {
                    UrlLocation.Value = Commerce.Common.Utility.GetSubcategoryRewriterUrl("sub", category.UrlFriendly, "a", "");
                }
                elem.Attributes.Append(UrlLocation);

               CategoryList.AppendChild(elem);
            }



            return doc.CreateNavigator().Select("/*");

            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// For retrieving only the top level categories.  Those have a parentID that is 0.
        /// </summary>
        /// <returns>XPathNodeIterator</returns>
        public static XPathNodeIterator CategoryTopLevelList()
        {
            try
            {

                //Create XML object
                XmlDocument doc = new XmlDocument();

                XmlElement CategoryList = (XmlElement)doc.AppendChild(doc.CreateElement("CategoryList"));


                foreach (Category category in new CategoryCollection().Load())
                {
                    if (category.ParentID == 0)
                    {
                        XmlElement elem = doc.CreateElement("Category");
                        XmlAttribute CategoryName = doc.CreateAttribute("CategoryName", "");
                        CategoryName.Value = category.CategoryName;
                        elem.Attributes.Append(CategoryName);

                        XmlAttribute CategoryID = doc.CreateAttribute("CategoryID", "");
                        CategoryID.Value = Convert.ToString(category.CategoryID);
                        elem.Attributes.Append(CategoryID);

                        XmlAttribute ParentID = doc.CreateAttribute("ParentID", "");
                        ParentID.Value = Convert.ToString(category.ParentID);
                        elem.Attributes.Append(ParentID);

                        XmlAttribute CategoryGUID = doc.CreateAttribute("CategoryGUID", "");
                        CategoryGUID.Value = Convert.ToString(category.CategoryGUID);
                        elem.Attributes.Append(CategoryGUID);

                        XmlAttribute CategoryUrlFriendly = doc.CreateAttribute("CategoryUrlFriendly", "");
                        CategoryUrlFriendly.Value = category.UrlFriendly;
                        elem.Attributes.Append(CategoryUrlFriendly);

                        XmlAttribute UrlLocation = doc.CreateAttribute("UrlLocation", "");
                        UrlLocation.Value = Commerce.Common.Utility.GetRewriterUrl("category", category.UrlFriendly, "");
                        elem.Attributes.Append(UrlLocation);

                        XmlAttribute listOrder = doc.CreateAttribute("ListOrder", "");
                        listOrder.Value = Convert.ToString(category.ListOrder);
                        elem.Attributes.Append(listOrder);

                        CategoryList.AppendChild(elem);
                    }
                }



                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// For retrieving the sub categories for a categoryID.  Those have a parentID that is categoryID.
        /// </summary>
        /// <param name="parentID">Parent category ID to get subcategories for.</param>
        /// <returns>XPathNodeIterator</returns>
        public static XPathNodeIterator CategorySubcategoriesList(string parentID, string parentName)
        {
            try
            {

                //Create XML object
                XmlDocument doc = new XmlDocument();

                XmlElement CategoryList = (XmlElement)doc.AppendChild(doc.CreateElement("CategoryList"));

                int catID = Int32.Parse(parentID);

                foreach (Category category in new CategoryCollection().Load())
                {
                    if (category.ParentID == catID)
                    {
                        XmlElement elem = doc.CreateElement("Category");
                        XmlAttribute CategoryName = doc.CreateAttribute("CategoryName", "");
                        CategoryName.Value = category.CategoryName;
                        elem.Attributes.Append(CategoryName);

                        XmlAttribute CategoryID = doc.CreateAttribute("CategoryID", "");
                        CategoryID.Value = Convert.ToString(category.CategoryID);
                        elem.Attributes.Append(CategoryID);

                        XmlAttribute ParentID = doc.CreateAttribute("ParentID", "");
                        ParentID.Value = Convert.ToString(category.ParentID);
                        elem.Attributes.Append(ParentID);

                        XmlAttribute CategoryGUID = doc.CreateAttribute("CategoryGUID", "");
                        CategoryGUID.Value = Convert.ToString(category.CategoryGUID);
                        elem.Attributes.Append(CategoryGUID);

                        XmlAttribute CategoryUrlFriendly = doc.CreateAttribute("CategoryUrlFriendly", "");
                        CategoryUrlFriendly.Value = category.UrlFriendly;
                        elem.Attributes.Append(CategoryUrlFriendly);

                        XmlAttribute ImageFile = doc.CreateAttribute("ImageFile", "");
                        ImageFile.Value = Convert.ToString(category.ImageFile);
                        elem.Attributes.Append(ImageFile);

                        XmlAttribute listOrder = doc.CreateAttribute("ListOrder", "");
                        listOrder.Value = Convert.ToString(category.ListOrder);
                        elem.Attributes.Append(listOrder);

                        XmlAttribute UrlLocation = doc.CreateAttribute("UrlLocation", "");
                        UrlLocation.Value = Commerce.Common.Utility.GetSubcategoryRewriterUrl("sub", category.UrlFriendly, parentName, "");

                        elem.Attributes.Append(UrlLocation);

                        CategoryList.AppendChild(elem);
                    }
                }



                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }


        /// <summary>
        /// For retrieving the sub categories for a categoryID.  Those have a parentID that is categoryID.
        /// </summary>
        /// <param name="parentID">Parent category ID to get subcategories for.</param>
        /// <returns>XPathNodeIterator</returns>
        public static XPathNodeIterator CategoryItem(string categoryID)
        {
            try
            {
                string categoryName = Commerce.Common.Utility.UnwindRewriteParam(categoryID);

                //Create XML object
                XmlDocument doc = new XmlDocument();

                XmlElement CategoryList = (XmlElement)doc.AppendChild(doc.CreateElement("CategoryList"));

                int catID;
                if (!int.TryParse(categoryID, out catID))
                {
                    catID = 0;
                }

                foreach (Category category in new CategoryCollection().Load())
                {
                    if (category.CategoryID == catID || category.UrlFriendly.ToLower().Equals(categoryID.ToLower())) // || category.CategoryName.ToLower().Equals(categoryName.ToLower()))
                    {
                        XmlElement elem = doc.CreateElement("Category");
                        XmlAttribute CategoryName = doc.CreateAttribute("CategoryName", "");
                        CategoryName.Value = category.CategoryName;
                        elem.Attributes.Append(CategoryName);

                        XmlAttribute CategoryID = doc.CreateAttribute("CategoryID", "");
                        CategoryID.Value = Convert.ToString(category.CategoryID);
                        elem.Attributes.Append(CategoryID);

                        XmlAttribute ParentID = doc.CreateAttribute("ParentID", "");
                        ParentID.Value = Convert.ToString(category.ParentID);
                        elem.Attributes.Append(ParentID);

                        XmlAttribute CategoryGUID = doc.CreateAttribute("CategoryGUID", "");
                        CategoryGUID.Value = Convert.ToString(category.CategoryGUID);
                        elem.Attributes.Append(CategoryGUID);

                        XmlAttribute CategoryUrlFriendly = doc.CreateAttribute("CategoryUrlFriendly", "");
                        CategoryUrlFriendly.Value = category.UrlFriendly;
                        elem.Attributes.Append(CategoryUrlFriendly);

                        XmlAttribute CategoryImageID = doc.CreateAttribute("CategoryImageID", "");
                        CategoryImageID.Value = category.ImageFile;
                        elem.Attributes.Append(CategoryImageID);

                        XmlAttribute UrlLocation = doc.CreateAttribute("UrlLocation", "");
                        if (ParentID.Value == "0")
                        {
                            UrlLocation.Value = Commerce.Common.Utility.GetRewriterUrl("category", category.UrlFriendly, "");
                        }
                        else
                        {
                            UrlLocation.Value = Commerce.Common.Utility.GetSubcategoryRewriterUrl("sub", category.UrlFriendly, "a", "");
                        }
                        elem.Attributes.Append(UrlLocation);

                        CategoryList.AppendChild(elem);

                        break;
                    }
                }



                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }


        /// <summary>
        /// JASON: THIS MAY NOT WORK...
        /// For retrieving the information about a single category.
        /// </summary>
        /// <param name="parentID">Category ID to get detail for.</param>
        /// <returns>XPathNodeIterator</returns>

        public static XPathNodeIterator CategoryDetail(string categoryID)
        {
            try
            {
                string categoryName = Commerce.Common.Utility.UnwindRewriteParam(categoryID);

                //Pull product from Subsonic object.
                CategoryCollection catList = new CategoryCollection().Load();
                //Category thisCategory = GetCategory(categoryID, catList);
                Category thisCategory = catList[0];
                
                int catID;
                if (!int.TryParse(categoryID, out catID))
                {
                    catID = 0;
                }

                foreach (Category category in new CategoryCollection().Load())
                {
                    if (category.CategoryID == catID || category.UrlFriendly.ToLower().Equals(categoryID.ToLower())) // || category.CategoryName.ToLower().Equals(categoryName.ToLower()))
                    {
                        thisCategory = category;
                    }
                }

                if (thisCategory == null)
                {
                    // If there's an exception we'll output an error element instead
                    XmlDocument errorDoc = new XmlDocument();
                    errorDoc.LoadXml(String.Format("<error>Null categoryID: '{0}'</error>", categoryID));
                    return errorDoc.CreateNavigator().Select(".");
                }

                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement root = (XmlElement)doc.AppendChild(doc.CreateElement("Category"));

                foreach (TableSchema.TableColumnSetting col in thisCategory.GetColumnSettings())
                {
                    string colValue = string.Empty;
                    string colName = thisCategory.GetSchema().GetColumn(col.ColumnName).PropertyName;

                    if (col.CurrentValue != null)
                        colValue = col.CurrentValue.ToString();


                    XmlAttribute ItemName = doc.CreateAttribute(colName, "");
                    ItemName.Value = colValue;
                    root.Attributes.Append(ItemName);
                }




                XmlElement CategoryList = (XmlElement)root.AppendChild(doc.CreateElement("CategoryList"));


                foreach (Category category in catList)
                {
                    if (category.CategoryID == thisCategory.ParentID)
                    {
                        XmlElement elem = doc.CreateElement("Category");
                        XmlAttribute CategoryName = doc.CreateAttribute("CategoryName", "");
                        CategoryName.Value = category.CategoryName;
                        elem.Attributes.Append(CategoryName);

                        XmlAttribute CategoryID = doc.CreateAttribute("CategoryID", "");
                        CategoryID.Value = Convert.ToString(category.CategoryID);
                        elem.Attributes.Append(CategoryID);

                        XmlAttribute ParentID = doc.CreateAttribute("ParentID", "");
                        ParentID.Value = Convert.ToString(category.ParentID);
                        elem.Attributes.Append(ParentID);

                        XmlAttribute CategoryGUID = doc.CreateAttribute("CategoryGUID", "");
                        CategoryGUID.Value = Convert.ToString(category.CategoryGUID);
                        elem.Attributes.Append(CategoryGUID);

                        XmlAttribute CategoryUrlFriendly = doc.CreateAttribute("CategoryUrlFriendly", "");
                        CategoryUrlFriendly.Value = category.UrlFriendly;
                        elem.Attributes.Append(CategoryUrlFriendly);

                        XmlAttribute UrlLocation = doc.CreateAttribute("UrlLocation", "");
                        if (ParentID.Value == "0")
                        {
                            UrlLocation.Value = Commerce.Common.Utility.GetRewriterUrl("category", category.UrlFriendly, "");
                        }
                        else
                        {
                            UrlLocation.Value = Commerce.Common.Utility.GetSubcategoryRewriterUrl("sub", category.UrlFriendly, thisCategory.UrlFriendly, "");
                        }
                        elem.Attributes.Append(UrlLocation);

                        CategoryList.AppendChild(elem);
                    }
                }



                return doc.CreateNavigator().Select("/*");

            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error><callstack></callstack>", System.Web.HttpUtility.HtmlEncode(e.ToString()), System.Web.HttpUtility.HtmlEncode(e.StackTrace)));
                return errorDoc.CreateNavigator().Select(".");
            }
        }


        public static XPathNodeIterator ManufacturerList()
        {

            try
            {

                //Create XML object
                XmlDocument doc = new XmlDocument();

                XmlElement ManufacturerList = (XmlElement)doc.AppendChild(doc.CreateElement("ManufacturerListList"));


                foreach (Manufacturer manufacturer in new ManufacturerCollection().Load())
                {

                    XmlElement elem = doc.CreateElement("Manufacturer");
                    XmlAttribute Manufacturer = doc.CreateAttribute("Manufacturer", "");
                    Manufacturer.Value = manufacturer.ManufacturerX;
                    elem.Attributes.Append(Manufacturer);

                    XmlAttribute ManufacturerID = doc.CreateAttribute("ManufacturerID", "");
                    ManufacturerID.Value = Convert.ToString(manufacturer.ManufacturerID);
                    elem.Attributes.Append(ManufacturerID);

                    ManufacturerList.AppendChild(elem);
                }

                return doc.CreateNavigator().Select("/*");

            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }


        /// <summary>
        /// Add single product to cart without options
        /// </summary>
        /// <param name="productID">productID</param>
        /// <param name="quantity">quantity</param>
        /// <returns>Total Items in the Cart</returns>
        public static string AddToCart(string productID, string quantity)
        {

            try
            {


                //Pull product from Subsonic object.
                Product prod = GetProduct(productID);

                prod.Quantity = int.Parse(quantity);
                OrderController.AddItem(prod);

                OrderItemCollection orderItemCollection = OrderController.GetCartItems();

                int totalItems = 0;
                foreach (var product in orderItemCollection)
                {
                    totalItems += product.Quantity;
                }

                return totalItems.ToString();

            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
               //XmlDocument errorDoc = new XmlDocument();
                //errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return "-1";
            }
        
        }

        /// <summary>
        /// Add multiple products to cart
        /// </summary>
        /// <param name="productIDsCSV">Comma separated productIDs</param>
        /// <param name="quantitiesCSV">Comma separated quanties - must be in same order as productIDs</param>
        /// <returns>Total Items in the Cart</returns>
        public static string AddToCartMultiple(string productIDsCSV, string quantitiesCSV)
        {
            try
            {
                string[] products = productIDsCSV.Split(',');
                string[] quantities = quantitiesCSV.Split(',');

                for (int i = 0; i < products.Length; i++)
                {
                    int qty = 0;
                    if (Int32.TryParse(quantities[i], out qty))
                    {
                        if (qty > 0)
                        {
                            //Pull product from Subsonic object.
                            Product prod = GetProduct(products[i]);

                            if (prod != null)
                            {
                                prod.Quantity = qty;
                                OrderController.AddItem(prod);
                            }
                        }
                    }
               }
                
                // Get the cart for the return value
                OrderItemCollection orderItemCollection = OrderController.GetCartItems();

                int totalItems = 0;
                foreach (var product in orderItemCollection)
                {
                    totalItems += product.Quantity;
                }

                return totalItems.ToString();
            }
            catch (Exception e)
            {
                //return String.Format("<error>{0}<callstack>{1}</callstack></error>", System.Web.HttpUtility.HtmlEncode(e.ToString()), System.Web.HttpUtility.HtmlEncode(e.StackTrace.ToString()));
                
                return "-1";
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="productID"></param>
        /// <param name="quantity"></param>
        /// <param name="options">Selected options in the form of 'id1:selectedoption1}id2:selectedoption2~selectedoption3'</param>
        /// <returns></returns>
        public static string AddToCartWithOptions(string productID, string quantity, string options)
        {

            try
            {


                //Pull product from Subsonic object.
                Product prod = GetProduct(productID);

                // Add selected quantity
                prod.Quantity = int.Parse(quantity);

                // Init the selected product options collection
                prod.SelectedAttributes = new Attributes();

                // Add option selections
                if (options.Length > 0)
                {
                    string[] productOptions = options.Split('}');
                    foreach (string po in productOptions)
                    {
                        string[] splitResults = po.Split(':');

                        // If only an ID (one item), then its likely a multiple select with no items selected.
                        if (splitResults.Length > 0)
                        {
                            int attrId;
                            if (Int32.TryParse(splitResults[0], out attrId))
                            {
                                AttributeController attrController = new AttributeController();
                                Commerce.Common.AttributeCollection attributes = attrController.FetchByQuery(new SubSonic.Query("CSK_Store_Attribute").WHERE("productAttributeID", SubSonic.Comparison.Equals, attrId));
                                Commerce.Common.Attribute attribute = attributes[0];
                                AttributeTemplate template = attribute.AttributeTemplate;
                                AttributeItemCollection templateItems = template.AttributeItemRecords();

                                attribute.Selections = new List<AttributeSelection>();

                                // TODO: Refactor and promote into the attribute class or something
                                if (template.AttributeTypeID == (int)AttributeType.UserInput)
                                {
                                    AttributeItem item = templateItems[0];

                                    AttributeSelection selection = new AttributeSelection();
                                    selection.Name = splitResults[1];
                                    selection.Value = item.AttributeItemId.ToString();
                                    selection.SkuAdjustment = item.SkuSuffix;
                                    selection.PriceAdjustment = item.Adjustment;

                                    attribute.Selections.Add(selection);
                                }
                                else
                                {
                                    string[] selelectOptions = splitResults[1].Split('~');
                                    foreach (string selectedOpt in selelectOptions)
                                    {
                                        int attrItemId = 0;
                                        if (Int32.TryParse(selectedOpt, out attrItemId))
                                        {
                                            SubSonic.Where w = new SubSonic.Where();
                                            w.ColumnName = AttributeItem.AttributeItemIdColumn.PropertyName;
                                            w.Comparison = SubSonic.Comparison.Equals;
                                            w.ParameterValue = attrItemId;

                                            AttributeItemCollection items = templateItems.Filter(w, true);

                                            //templateItems.Where(AttributeItem.AttributeItemIdColumn.PropertyName, Comparison.Equals, attrItemId).Filter();
                                            if (templateItems.Count > 0)
                                            {
                                                AttributeItem item = templateItems[0];

                                                AttributeSelection selection = new AttributeSelection();
                                                selection.Name = item.Name;
                                                selection.Value = selectedOpt;
                                                selection.SkuAdjustment = item.SkuSuffix;
                                                selection.PriceAdjustment = item.Adjustment;

                                                attribute.Selections.Add(selection);
                                            }

                                            templateItems = template.AttributeItemRecords();
                                        }
                                    }
                                }

                                prod.SelectedAttributes.Add(attribute);
                            }
                        }
                    }
                }

                OrderController.AddItem(prod);

                OrderItemCollection orderItemCollection = OrderController.GetCartItems();

                int totalItems = 0;
                foreach (var product in orderItemCollection)
                {
                    totalItems += product.Quantity;
                }

                return totalItems.ToString();

            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                //XmlDocument errorDoc = new XmlDocument();
                //errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return "-1";
            }

        }


        /// <summary>
        /// Total Items in the Cart
        /// </summary>
        /// <returns>Total Items in the Cart</returns>
        public static string GetCartItemsCount()
        {
            try
            {
                // Get the cart for the return value
                OrderItemCollection orderItemCollection = OrderController.GetCartItems();

                int totalItems = 0;
                foreach (var product in orderItemCollection)
                {
                    totalItems += product.Quantity;
                }

                return totalItems.ToString();
            }
            catch (Exception e)
            {
                return "-1";
            }
        }


        /// <summary>
        /// Get Url in the config that the cart goes to
        /// </summary>
        /// <returns>URL</returns>
        public static string GetCartUrl()
        {
            return Utility.GetCartUrl();
        }

        /// <summary>
        /// Get Url in the config that the cart goes to
        /// </summary>
        /// <returns>URL</returns>
        public static string GetCheckoutUrl()
        {
            return Utility.GetCheckoutUrl();
        }

        private static Product GetProduct (string p)
        {

            Commerce.Common.Product product = null;
            try
            {

                int productID;
                string productSku;
                Guid productGUID;

                string sProductGUID = "";

                if (IsGUID(p))
                    sProductGUID = p;

                if (int.TryParse(p, out productID) == false)
                    productID = 0;

                productSku = p;

                if (sProductGUID != string.Empty)
                {
                    productGUID = new Guid(sProductGUID);
                    product = ProductController.GetProductDeepByGUID(productGUID);
                }
                else if (productID != 0)
                {
                    product = ProductController.GetProductDeep(productID);
                }
                else if (productSku != string.Empty)
                {
                    product = ProductController.GetProductDeep(productSku);
                }
            
                //make sure we have a product
                TestCondition.IsTrue(product.IsLoaded, "Invalid url/product id");
                

            }
            catch (Exception)
            {
                //To Do.
                //Response.Write(ex.Message + ex.StackTrace);
                //throw ex;
                //ExceptionPolicy.HandleException(ex, "Application Exception");
                //Response.Redirect(Page.ResolveUrl("~/ExceptionPage.aspx"), false);
            }

            return product;
        }



        private static Category GetCategory(string c, CategoryCollection catList)
        {

            Commerce.Common.Category category = null;
            try
            {

                int categoryID;
                string categoryName;
                //Guid categoryGUID;

                //string sCategoryGUID = "";

                //if (IsGUID(c))
                //    sCategoryGUID = c;

                if (int.TryParse(c, out categoryID) == false)
                    categoryID = 0;

                categoryName = c;

                //if (sCategoryGUID != string.Empty)
                //{
                //    //categoryGUID = new Guid(sCategoryGUID);
                //    //category = CategoryController.(categoryGUID);
                //}
                //else 
                if (categoryID != 0)
                {
                    //category = CategoryController.Find(categoryID);
                    foreach (Category cat in catList)
                    {
                        if( cat.CategoryID == categoryID )
                        {
                            category = cat;
                            break;
                        }
                    }
                }
                else if (!String.IsNullOrEmpty(categoryName))
                {
                    //category = CategoryController.FindByName(categoryName.ToLower());
                    foreach (Category cat in catList)
                    {
                        if (cat.CategoryName.ToLower().Equals(categoryName.ToLower()))
                        {
                            category = cat;
                            break;
                        }
                    }
                }

                //make sure we have a category
                TestCondition.IsTrue(category.IsLoaded, "Invalid url/category id");


            }
            catch (Exception)
            {
                //To Do.
                //Response.Write(ex.Message + ex.StackTrace);
                //throw ex;
                //ExceptionPolicy.HandleException(ex, "Application Exception");
                //Response.Redirect(Page.ResolveUrl("~/ExceptionPage.aspx"), false);
            }

            return category;
        }


        public static bool IsGUID(string expression)
        {
            if (expression != null)
            {
                Regex guidRegEx = new Regex(@"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$");

                return guidRegEx.IsMatch(expression);
            }
            return false;
        }



    }
}